#pragma once
#include <memory>
#include <mutex>
#include <vector>
namespace xncc {
namespace shared {
    template <class C>
    class ObjectPool
    {
        using P = std::shared_ptr<C>;

      public:
        ObjectPool(std::size_t capacity) : capacity_(capacity), size_(0) {}
        ~ObjectPool() {}

      public:
        std::size_t capacity() const { return capacity_; }

        P borrowObject()
        {
            std::lock_guard<std::mutex> lk(mutex_);

            if (!pool_.empty()) {
                P pObject = pool_.back();
                pool_.pop_back();
                return pObject;
            }

            if (size_ >= capacity_) {
                return nullptr;
            }
            P pObject = std::make_shared<C>();
            size_++;
            return pObject;
        }

        void returnObject(P pObject)
        {
            std::lock_guard<std::mutex> lk(mutex_);
            if (pool_.size() < capacity_) {
                pool_.push_back(pObject);
            }
            size_--;
        }

        std::size_t size() const
        {
            std::lock_guard<std::mutex> lk(mutex_);
            return size_;
        }
        std::size_t available() const
        {
            std::lock_guard<std::mutex> lk(mutex_);

            return pool_.size() - size_;
        }

      private:
        // 不允许拷贝构造和默认构造
        ObjectPool()                             = delete;
        ObjectPool(const ObjectPool&)            = delete;
        ObjectPool& operator=(const ObjectPool&) = delete;

      private:
        std::vector<P>     pool_;
        mutable std::mutex mutex_;
        std::size_t        capacity_;
        std::size_t        size_;
    };
}  // namespace shared
}  // namespace xncc